/*
  (C) 2005 Adam D. Bradley

  This program is free software; you can redistribute it and/or
  modify it under the terms of Version 2 of the GNU General Public 
  License.
  
  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  General Public License for more details.
  
  You should have received a copy of the GNU Library General Public
  License along with this library; if not, write to the Free
  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package step;

import java.util.ArrayList;

import sxe.SxeMonitor;
import snbenchlib.Log;
import snbenchlib.Trace;
import snobject.snBoolean;


public class TriggerNode extends AbstractTrigger
{
	public TriggerNode(String id)  { super(id); }
	public TriggerNode() { super(); }

	protected void SetWanted(boolean v) { 
		rt_wanted = v; 
		/* 
		 * Do not descend!
		 * children's wanted flags are under our control 
		 */
	}

	public boolean IsEnabled() {
		switch(state) {
		case ASLEEP:
			// mjo: prevent triggers from always running 
			// regardless of parenting
			return rt_wanted;
		case TESTING:
			return HasFreshInput(0);
		case PROCESSING:
			return HasFreshInput(1);
		case DONE:
			return false;
		}
		assert(false);
		return false; /* should never happen */
	}

	public void Evaluate() throws EvaluationFailure {
		int oldstate = state; 
			
		switch(state) {
		case ASLEEP:
			children[0].ClearEvaluatedFlags();
			children[1].ClearEvaluatedFlags();
			children[1].SetWanted(false);
			children[0].SetWanted(true);
			ClearFreshInputs();
			state = TESTING;
			break;
			
		case TESTING:
			/* big oops */
			if (snBoolean.TRUE.equals(GetInput(0))) {
				children[0].SetWanted(false);
				children[1].SetWanted(true);
				state = PROCESSING;
			} else {
				state = ASLEEP;
			}
			break;
			
		case PROCESSING:
			SetValue(GetInput(1));
			PushResult();
			state = DONE;
			
			/* this is where we should:
			 * 
			 * 1) see if we are a root node
			 * 2) tell the SSD that this tree is complete
			 * 3) further instruction will come from the SSD,
			 * 		for now, mark this and all children as garbage
			 */
			if(parents.length==0){
				
				SxeMonitor.reportEvaluationComplete(this.getGraphID());
				
				ArrayList<Node> al = new ArrayList<Node>();
				al.add(this);
				while(!al.isEmpty()){
					Node n = al.remove(0);
					n.markAsGarbage();
					SxeMonitor.incrAvailableResources(n.getCost());
					
					if(!(n instanceof LastTriggerEval)){
						for(int i=0;i<n.children.length;i++){
							al.add(n.children[i]);
						}
					}
				}
			}

			
			break;
			
		default:
			assert(false);
		}
		Log.evaluator.log(
				"Trigger "+ super.ID + " state advancement from " + StateName(oldstate) + " to " + StateName(state),
				Trace.VERBOSE);
	}


	// Serializer
	public String TagName() { return "trigger"; }
	
	@Override
	public Node ShallowCopy() {
		TriggerNode cn = new TriggerNode(ID);
		Node.CopyNonRTPropertiesFromAtoB(this,cn);
		return cn;
	}
}
